/*
 * 
 */
package megamek.client.bot;

import static org.junit.Assert.*;

import java.util.Vector;

import megamek.common.BipedMech;
import megamek.common.Board;
import megamek.common.Coords;
import megamek.common.Entity;
import megamek.common.GameTurn;
import megamek.common.Hex;
import megamek.common.IGame;
import megamek.common.INarcPod;
import megamek.common.Player;
import megamek.common.Protomech;
import megamek.common.QuadMech;
import megamek.common.Tank;
import megamek.common.actions.BrushOffAttackAction;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * The class <code>PhysicalCalculatorTest</code> contains tests for the class
 * <code>{@link PhysicalCalculator}</code>.
 * 
 * @generatedBy CodePro at 5/16/14 9:19 PM
 * @author cbandell
 * @version $Revision: 1.0 $
 */
public class PhysicalCalculatorTest
{
	private static TestBot bot = new TestBot("optimus", "localhost", 1234);
	private static Player optimus, megatron;
	private static Entity tank = new Tank();
	private static Entity protomech, enemyTank;
	private static Vector<Entity> megatronInventory = new Vector<Entity>();

	/**
	 * Sets the up before class.
	 * 
	 * @throws Exception
	 *             the exception
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
		// add a player to the game
		optimus = new Player(1, "optimus");
		final IGame game = bot.game;
		game.addPlayer(0, optimus);
		game.setPhase(IGame.Phase.PHASE_FIRING);
		bot.local_pn = 0;

		// create the bad guy
		megatron = new Player(2, "megatron");
		bot.game.addPlayer(2, megatron);

		protomech = new Protomech();
		enemyTank = new Tank();
		protomech.setOwner(megatron);
		protomech.setId(5);
		enemyTank.setOwner(megatron);
		enemyTank.setId(6);
		megatronInventory.add(protomech);
		megatronInventory.add(enemyTank);


		// set the game board to an height of 3 and width of 3
		bot.game.setBoard(new Board(3, 3));
		
		// need to set all the hex on the board
		for (int i = 0; i < bot.game.getBoard().getWidth(); i++)
		{
			for (int j = 0; j < bot.game.getBoard().getHeight(); j++)
			{
				Coords coords = new Coords(i, j);
				bot.game.getBoard().setHex(coords, new Hex(0));
			}
		}

	}

	private static void resetTurn(Entity entity, int entityId)
	{
		// this need to be preformed in this order every time the entity vector
		// needs to be reset.
		entity.setId(entityId);
		entity.setOwner(optimus);

		Vector<Entity> entities = new Vector<Entity>();
		entities.add(entity);
		entities.addAll(megatronInventory);
		bot.game.setEntitiesVector(entities);
		// set it to optimus' turn
		bot.game.resetTurnIndex();
		bot.game.insertNextTurn(new GameTurn.SpecificEntityTurn(optimus.getId(), entity.getId()));
		bot.game.changeToNextTurn();
	}

	/**
	 * Run the PhysicalOption calculatePhysicalTurn(TestBot) method test.
	 * 
	 * @throws Exception
	 * 
	 * @generatedBy CodePro at 5/16/14 9:19 PM
	 */
	@Test
	public void testCalculatePhysicalTurn_1() throws Exception
	{
		// set the tank's id and add it to optimus' inventory
		resetTurn(tank, 1);

		// create the physical option for a tank
		PhysicalOption expected = new PhysicalOption(tank);
		PhysicalOption result = PhysicalCalculator.calculatePhysicalTurn(bot);

		// make sure the result and expected are not null and that they equal
		assertNotNull(result);
		assertNotNull(expected);
		assertEquals(expected, result);
	}

	/**
	 * Run the PhysicalOption calculatePhysicalTurn(TestBot) method test.
	 * 
	 * @throws Exception
	 *             the exception
	 * @generatedBy CodePro at 5/16/14 9:19 PM
	 */
	@Test
	public void testCalculatePhysicalTurn_2() throws Exception
	{
		// create a QuadMech object and add it to optimus' inventory
		Entity quadMech = new QuadMech();
		resetTurn(quadMech, 2);

		PhysicalOption expected = new PhysicalOption(quadMech);
		PhysicalOption result = PhysicalCalculator.calculatePhysicalTurn(bot);

		// make sure the result and expected are not null and that they equal
		assertNotNull(result);
		assertNotNull(expected);
		assertEquals(expected, result);
	}

	/**
	 * Run the PhysicalOption calculatePhysicalTurn(TestBot) method test.
	 * 
	 * @throws Exception
	 * 
	 * @generatedBy CodePro at 5/16/14 9:19 PM
	 */
	@Test
	public void testCalculatePhysicalTurn_3() throws Exception
	{

		// create a QuadMech object and add it to optimus' inventory
		Entity biped = new BipedMech();
		biped.setSwarmAttackerId(enemyTank.getId());

		resetTurn(biped, 2);

		// add INarcPods to the mech
		final INarcPod bestPod = new INarcPod(biped.getOwner().getTeam(), INarcPod.HOMING, 0);
		biped.attachINarcPod(bestPod);
		biped.newRound(1);
		System.out.println("quadMech.hasINarcPodsAttached() " + biped.hasINarcPodsAttached());

		resetTurn(biped, 2);

		// the damage the Mech can inflict
		double damage = BrushOffAttackAction.getDamageFor(biped, BrushOffAttackAction.LEFT);
		PhysicalOption expected = new PhysicalOption(biped, bestPod, damage, PhysicalOption.BRUSH_LEFT, null);
		PhysicalOption result = PhysicalCalculator.calculatePhysicalTurn(bot);

		// make sure the result and expected are not null and that they equal
		assertNotNull(result);
		assertNotNull(expected);
		assertEquals(expected, result);
	}

	/**
	 * Run the PhysicalOption calculatePhysicalTurn(TestBot) method test.
	 * 
	 * @throws Exception
	 * 
	 * @generatedBy CodePro at 5/16/14 9:19 PM
	 */
	@Test
	public void testCalculatePhysicalTurn_4() throws Exception
	{

		// create a QuadMech object and add it to optimus' inventory
		Entity biped = new BipedMech();
		biped.setSwarmAttackerId(protomech.getId());

		resetTurn(biped, 2);

		// add INarcPods to the mech
		final INarcPod bestPod = new INarcPod(biped.getOwner().getTeam(), INarcPod.ECM, 0);
		biped.attachINarcPod(bestPod);
		biped.newRound(1);
		System.out.println("quadMech.hasINarcPodsAttached() " + biped.hasINarcPodsAttached());

		resetTurn(biped, 2);

		// the damage the Mech can inflict
		double damage = BrushOffAttackAction.getDamageFor(biped, BrushOffAttackAction.LEFT);
		PhysicalOption expected = new PhysicalOption(biped, bestPod, damage, PhysicalOption.BRUSH_LEFT, null);
		PhysicalOption result = PhysicalCalculator.calculatePhysicalTurn(bot);

		// make sure the result and expected are not null and that they equal
		assertNotNull(result);
		assertNotNull(expected);
		assertEquals(expected, result);
	}

	@Test
	public void testGetBestPhysicalAttack_1() throws Exception
	{

		// if from entity is a tank or Infantry it should return null
		PhysicalOption result = PhysicalCalculator.getBestPhysicalAttack(tank, enemyTank, bot.game);
		assertNull("should be null", result);

		Entity attacker = new BipedMech();
		final Coords startingCoords = bot.getStartingCoords();
		attacker.setPosition(startingCoords);
		attacker.setElevation(1);
		attacker.setSwarmAttackerId(enemyTank.getId());

		Coords tankStartingCoords = bot.getStartingCoords();
		while (tankStartingCoords.equals(startingCoords))
		{
			// this loop will run until the 2 coords are different. this is to
			// ensure that 2 entities are not position on the same hex
			tankStartingCoords = bot.getStartingCoords();
		}
		enemyTank.setPosition(tankStartingCoords);
		enemyTank.setFacing(5);

		resetTurn(attacker, 10);

		result = PhysicalCalculator.getBestPhysicalAttack(attacker, enemyTank, bot.game);
		assertNull(result);
	}

	/**
	 * Run the PhysicalOption calculatePhysicalTurn(TestBot) method test.
	 * 
	 * @throws Exception
	 * 
	 * @generatedBy CodePro at 5/16/14 9:19 PM
	 */
	@Test
	public void testCalculatePhysicalTurn_6() throws Exception
	{

		PhysicalOption result = PhysicalCalculator.calculatePhysicalTurn(bot);

		// add additional test code here
		// An unexpected exception was thrown in user code while executing this
		// test:
		// java.lang.NullPointerException
		// at
		// megamek.client.bot.PhysicalCalculator.getBestPhysical(PhysicalCalculator.java:75)
		// at
		// megamek.client.bot.PhysicalCalculator.calculatePhysicalTurn(PhysicalCalculator.java:53)
		assertNotNull(result);
	}

	/**
	 * Perform pre-test initialization.
	 * 
	 * @throws Exception
	 *             if the initialization fails for some reason
	 * 
	 * @generatedBy CodePro at 5/16/14 9:19 PM
	 */
	@Before
	public void setUp() throws Exception
	{
		// add additional set up code here
	}

	/**
	 * Perform post-test clean-up.
	 * 
	 * @throws Exception
	 *             if the clean-up fails for some reason
	 * 
	 * @generatedBy CodePro at 5/16/14 9:19 PM
	 */
	@After
	public void tearDown() throws Exception
	{
		// Add additional tear down code here
	}

	/**
	 * Launch the test.
	 * 
	 * @param args
	 *            the command line arguments
	 * 
	 * @generatedBy CodePro at 5/16/14 9:19 PM
	 */
	public static void main(String[] args)
	{
		new org.junit.runner.JUnitCore().run(PhysicalCalculatorTest.class);
	}
}